#include "comm.h"
//#include "r_cg_sau.h"
#include "machine_stat.h"
#include "string.h"

//#include "sys_process.h"
#include "display.h"
#include "custom_define.h"
#include "open_power_code.h"
#include "protocal.h"

uint8_t CheckPackCmd(uint8_t *pack_buf, uint8_t cmd){
    return (pack_buf[PACK_CMD_OFFSET] == cmd);
}

void COM_SendACK(Comm_t *com){
   COM_Send(com, TEXT_ACK, 0);
}

void COM_SendNAK(Comm_t *com){
   COM_Send(com, TEXT_NAK, 0);
}

void COM_Send(Comm_t *com, uint8_t cmd, uint8_t len){	
    com->send_buf[0] = PACK_STX;
	com->send_buf[1] = PACK_SORT;
	com->send_buf[PACK_SIZE_OFFSET] = len;
	com->send_buf[PACK_CMD_OFFSET] = cmd;
	com->send_buf[4+len] = PACK_ETX;
    com->send_buf[5+len] = checksum(com->send_buf+1, len+4);
    com->SendLen = len+6;
    com->SendIndex = 0;
    com->Timeout = SEND_TIMEOUT;
    com->SendState = SEND_STA_START;
}
void COM_Init(Comm_t *com){
    com->Timeout = 0;
    com->Sm = SM_SEND_IDLE;
    com->SendState = SEND_STA_IDLE;
    
    com->RecvSm = SM_RECV_STX;
    com->RecvIndex = 0;
	memset(com->RecvBuff, 0, sizeof(com->RecvBuff));
	memset(com->send_buf, 0, sizeof(com->send_buf));
}

uint8_t COM_IsBusy(Comm_t *com){
   return (com->Sm != SM_SEND_IDLE);
}

/** @brief 关闭重发，待本次通信完成后自动打开重发 */
void COM_DisableRetry(Comm_t *com){
    com->DisableRetry = 1;
}
/** @brief  */
void COM_Fsm(Comm_t *com){
	if(com->Timeout) com->Timeout--;
    
	switch(com->Sm){
		case SM_SEND_IDLE:
		     if(com->SendState == SEND_STA_START){
				com->SendState = SEND_STA_RUN;
				if(com->DisableRetry==1)
				    com->RetryCount = 1;
				else	
				    com->RetryCount = RETRY_COUNT_MAX;
				com->Sm = SM_SEND_START; 
			 }else if(com->RecvBuff[0] != 0){
				if(com->ReceiveFunc != 0){
				    com->send_buf[0] = 0;
				    com->ReceiveFunc(com);
                    com->RecvBuff[0] = 0;
					if(com->send_buf[0] != 0){
                        com->SendState = SEND_STA_RUN;
						com->Sm = SM_SEND_START;
					}
				}
			 }
			break;
		case SM_SEND_START:
		     if(com->RetryCount-- > 0){
				com->PhySendByte(com->send_buf[0]);
				com->SendIndex = 1;
				com->Timeout = SEND_TIMEOUT;
				com->Sm = SM_SEND_END;	
			 }else{
			    com->Sm = SM_SEND_FINISH;
             }
			break;
        case SM_SEND_END:
		     if(com->SendIndex == com->SendLen){  
				if(CheckPackCmd(com->send_buf, TEXT_ACK) || 
				   CheckPackCmd(com->send_buf, TEXT_NAK) ||
				   CheckPackCmd(com->send_buf, TEXT_RES) ){   /* 发送的是对主机的回应, 则不需要等待接收 */
                   com->Sm = SM_SEND_FINISH;
				}else{
					com->Timeout = ACK_TIMEOUT;	
					com->Sm = SM_SEND_ACK;
				}
			 }else if(com->Timeout == 0){  /* 发送超时 */
			    com->Sm = SM_SEND_FINISH;
			 }
			 break;	
		case SM_SEND_ACK:
			 if(com->Timeout == 0){ /* 超时未响应 */
                 com->Sm = SM_SEND_START;
			 }else if(CheckPackCmd(com->send_buf, TEXT_GET)){/* GET */
				 if(CheckPackCmd(com->RecvBuff, TEXT_NAK)){
                      com->Sm = SM_SEND_START;
				 }else if(CheckPackCmd(com->RecvBuff, TEXT_RES)){
					com->ReceiveFunc(com);
					com->RecvBuff[0] = 0; 
					com->Sm = SM_SEND_FINISH;
				 }		 
			 }else if(CheckPackCmd(com->send_buf, TEXT_SET) || CheckPackCmd(com->send_buf, TEXT_INF)){
				 if(CheckPackCmd(com->RecvBuff, TEXT_NAK)){
                      com->Sm = SM_SEND_START;
				 }else if(CheckPackCmd(com->RecvBuff, TEXT_ACK)){
                    com->RecvBuff[0] = 0; 
					com->Sm = SM_SEND_FINISH;
				 }				
			 }
		     break;	
		case SM_SEND_FINISH:
		     com->SendState = SEND_STA_IDLE;
		     com->DisableRetry = 0;
			 com->Sm = SM_SEND_IDLE;
		     break;	  
		default:
			break;
	}
}

uint8_t checksum1(uint8_t *buf,uint8_t size1)
{
	uint8_t remainder = 0;
	uint8_t i;

	for (i = 0; i < size1; i++)
		remainder ^= buf[i];

	return (remainder);
	
}
uint8_t checksum(uint8_t *buf,uint8_t size1)
{
	uint8_t remainder = 0;
	uint8_t i;

	for (i = 0; i < size1; i++)
		remainder ^= buf[i];

	return (remainder);
	
}

void  COM_ReceivedISR(Comm_t *com, uint8_t recv_data){
uint8_t bcc;
    com->RecvBuffTemp[com->RecvIndex++] = recv_data;
	switch (com->RecvSm){
	case SM_RECV_STX:
		if(recv_data == PACK_STX){
			com->RecvSm = SM_RECV_SORT;
		}else
		    ResetRecvFsm(com);
		break;
	case SM_RECV_SORT:
		if(recv_data == PACK_SORT)
			com->RecvSm = SM_RECV_LENGTH;
		else
			ResetRecvFsm(com);
		break;
	case SM_RECV_LENGTH:
		if((recv_data+6) <= COMM_RECV_BUF_SIZE){
			com->RecvSm = SM_RECV_COMMAND;
			com->DataLength = recv_data;
		}else
			ResetRecvFsm(com);
		break;
	case SM_RECV_COMMAND:
		if(IsCommandValid(recv_data)){
			if(com->DataLength == 0)
			    com->RecvSm = SM_RECV_ETX;
			else	
			    com->RecvSm = SM_RECV_TEXT;
		}else
			ResetRecvFsm(com);
		break;
	case SM_RECV_TEXT:
		if(com->DataLength == 1)
			com->RecvSm = SM_RECV_ETX;
		com->DataLength--;
		break;
	case SM_RECV_ETX:
		if(recv_data == PACK_ETX)
			com->RecvSm = SM_RECV_BCC;
		else
			ResetRecvFsm(com);
		break;
	case SM_RECV_BCC: 
        bcc = checksum1(com->RecvBuffTemp+1, com->RecvBuffTemp[2]+5);
	 	if(bcc == 0){
	 		memcpy( com->RecvBuff, com->RecvBuffTemp, com->RecvBuffTemp[2]+6);
	 	}
		ResetRecvFsm(com);
		break;
	}
}

void COM_SentISR(Comm_t *com){
	if(com->SendIndex < com->SendLen){
		com->PhySendByte(com->send_buf[com->SendIndex]);
		com->SendIndex++;
	}
}



